package org.liveboardgames.agricola.domain.farm;

import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.liveboardgames.agricola.domain.card.Card;
import org.liveboardgames.agricola.domain.card.ImprovementCard;
import org.liveboardgames.agricola.domain.common.IResourceContainer;
import org.liveboardgames.agricola.model.structure.Visitable;
import org.liveboardgames.agricola.model.structure.Visitor;

public class Farm implements Serializable, Visitable, IResourceContainer {

  private Long id;

  private Map<String, Integer> resources;

  private List<FarmTile> tiles;

  private Set<Card> playedCards;

  /**
   * We do not want an external call to set the id of the game for us, but
   * rather let Hibernate handle it itself.
   * 
   * @param id
   *          the {@link #id} to set
   */
  public void setId(Long id) {
    this.id = id;
  }

  /**
   * @return the {@link #id}
   */
  public Long getId() {
    return id;
  }

  /**
   * @return the {@link #resources}
   */
  public Map<String, Integer> getResources() {
    return resources;
  }
  
  public int getResourceQuantity(String resourceType) {
    Integer resource = this.resources.get(resourceType);
    if (resource == null) {
      resource = new Integer(0);
    }
    return resource;
  }

  /**
   * @param resources
   *          the {@link #resources} to set
   */
  public void setResources(Map<String, Integer> resources) {
    this.resources = resources;
  }

  /**
   * @return the {@link #tiles}
   */
  public List<FarmTile> getTiles() {
    return tiles;
  }

  /**
   * @param tiles
   *          the {@link #tiles} to set
   */
  public void setTiles(List<FarmTile> tiles) {
    this.tiles = tiles;
  }

  public FarmTile getTileAt(Long tileId) {
    FarmTile tile = null;
    if (tiles != null && tiles.size() > tileId) {
      tile = this.tiles.get(tileId.intValue());
    }
    return tile;
  }

  /**
   * @return the {@link #playedCards}
   */
  public Set<Card> getPlayedCards() {
    return playedCards;
  }

  /**
   * @param playedCards
   *          the {@link #playedCards} to set
   */
  public void setPlayedCards(Set<Card> playedCards) {
    this.playedCards = playedCards;
  }

  public void acceptVisit(Visitor visitor) {
    visitor.visit(this);

    if (this.playedCards != null) {
      for (Card card : this.playedCards) {
        card.acceptVisit(visitor);
      }
    }

    if (this.tiles != null) {
      for (FarmTile tile : this.tiles) {
        tile.acceptVisit(visitor);
      }
    }
  }

  public void addResource(String type, Integer quantity) {
    if (this.resources == null) {
      this.resources = new HashMap<String, Integer>();
    }
    Integer currentQuantity = this.resources.get(type);
    this.resources.put(type, Math.max(0, currentQuantity + quantity));
  }

  public void addResources(Map<String, Integer> resources) {
    if (resources != null) {
      for (String type : resources.keySet()) {
        addResource(type, resources.get(type));
      }
    }
  }
  
  public void addPlayedCard(Card card) {
    if (this.playedCards == null) {
      this.playedCards = new HashSet<Card>();
    }
    this.playedCards.add(card);
  }

  public void removePlayedCard(ImprovementCard card) {
    if (this.playedCards != null && this.playedCards.contains(card)) {
      this.playedCards.remove(card);
    }
  }

}
